/* Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
 */
#include "stdafx.h"
#include "UDP.h"

#include <winsock.h>
#include <zlib.h>
#include <thread>

#include <ppl.h>

#pragma comment(lib,"ws2_32.lib") 
#pragma comment(lib,"D:/U/Project/packages/zlib_static.1.2.11.5/build/native/lib/x64/v142/Debug/MultiThreadedDebug/zlib.lib")


#include "../插座/材质纹理插座.h"


static uvec2 图像大小 = {512, 512};


static inline S_网络监听 f_创建UDP网络监听(uint16 端口) {
    S_网络监听 obj = {};
    WSADATA wsaData;

    obj.m_网络监听 = (S_结构对象指针)socket(AF_INET, SOCK_DGRAM, 0);

    SOCKADDR_IN* saClient = (SOCKADDR_IN*)malloc(sizeof(SOCKADDR_IN));
    saClient->sin_family = AF_INET;
    saClient->sin_port = htons(端口);             //发送端使用的发送端口，可以根据需要更改
    saClient->sin_addr.s_addr = htonl(INADDR_ANY);


    obj.m_接收数据地址 = (S_结构对象指针)saClient;


    obj.m_接收数据量 = sizeof(SOCKADDR_IN);
    if (bind((SOCKET)obj.m_网络监听, (SOCKADDR FAR*)obj.m_接收数据地址, obj.m_接收数据量) != 0) {
        std::cout << "绑定端口初始化失败" << std::endl;
    }

    return obj;
}




static inline S_网络监听 f_创建TCP网络监听(uint16 端口) {
    S_网络监听 obj = {};
    WSADATA wsaData;

    obj.m_网络监听 = (S_结构对象指针)socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN* saClient = (SOCKADDR_IN*)malloc(sizeof(SOCKADDR_IN));
    saClient->sin_family = AF_INET;
    saClient->sin_port = htons(端口);             //发送端使用的发送端口，可以根据需要更改
    saClient->sin_addr.s_addr = htonl(INADDR_ANY);


    obj.m_接收数据地址 = (S_结构对象指针)saClient;


    obj.m_接收数据量 = sizeof(SOCKADDR);
    if (bind((SOCKET)obj.m_网络监听, (SOCKADDR*)obj.m_接收数据地址, obj.m_接收数据量) != 0) {
        std::cout << "绑定端口初始化失败" << std::endl;
    }

    if (listen((SOCKET)obj.m_网络监听, SOMAXCONN) < 0) {
        std::cout << "设置监听状态失败！" << std::endl;
    } else {
        std::cout << "设置监听状态成功！" << std::endl;
    }



    

    return obj;
}





static void f_接收UDP数据线程(C_UDP接收图像节点* node) {
    int8* pszRecv = new int8[4096];

    while (node->m_运行线程) {
        node->m_像素.resize(512 * 512);
        auto* p = (uint8*)(node->m_像素.data());
        uint8 转换指针[1024];

        int32 nbSize = 0;
        
        for (uint32 i = 0; i < 512; ++i) {
            
            if ((nbSize = recvfrom((SOCKET)node->m_网络.m_网络监听, pszRecv, 4096, 0, (SOCKADDR FAR*)node->m_网络.m_接收数据地址, &node->m_网络.m_接收数据量)) != SOCKET_ERROR) {
                //uLongf len_dest = 1024;
                //auto errComp = uncompress(转换指针, &len_dest, (uint8*)pszRecv, nbSize);
                uint16 行ID = *((uint16*)pszRecv);
                //std::cout<< 行ID<<std::endl;
                memcpy(&p[512 * 行ID], pszRecv, 512);
            }
        }
        //std::cout << "接收数据 : " << nbSize << std::endl;
        node->m_写入记录 = true;
        
    }

    delete pszRecv;
}



static void f_接收TCP数据线程(C_UDP接收图像节点* node) {
    int8* pszRecv = new int8[3145728];

    SOCKADDR_IN* 接收端地址 = (SOCKADDR_IN*)malloc(sizeof(SOCKADDR_IN));
    接收端地址->sin_family = AF_INET;
    接收端地址->sin_port = htons(8000);             //发送端使用的发送端口，可以根据需要更改
    接收端地址->sin_addr.s_addr = htonl(INADDR_ANY);

    int32 接收数据量 = sizeof(SOCKADDR);
    auto s_accept = accept((SOCKET)node->m_网络.m_网络监听, (SOCKADDR*)接收端地址, &接收数据量);
    if (s_accept != SOCKET_ERROR) {
        std::cout << "连接成功" << std::endl;
    }

    while (node->m_运行线程) {
        node->m_像素.resize(512 * 512);
        auto* p = (uint8*)(node->m_像素.data());
        uint8 转换指针[512 * 512 * 3];

        int32 nbSize = 0;

        nbSize = recv(s_accept, pszRecv, 3145728, 0);
        if (nbSize > 0) {
            std::cout << "客户端信息:" << nbSize << std::endl;
            uLongf len_dest = 256*256*3;
            auto errComp = uncompress(转换指针, &len_dest, (uint8*)pszRecv, nbSize);

        } else if (nbSize == 0) {
            closesocket(s_accept);
            s_accept = accept((SOCKET)node->m_网络.m_网络监听, (SOCKADDR*)接收端地址, &接收数据量);
            if (s_accept == SOCKET_ERROR) {
                std::cout << "连接失败！" << std::endl;
            }
            std::cout << "重新连接" << std::endl;
        }
        


        /*for (uint32 i = 0; i < 768; ++i) {

            if ((nbSize = recvfrom((SOCKET)node->m_网络.m_网络监听, pszRecv, 4096, 0, (SOCKADDR FAR*)node->m_网络.m_接收数据地址, &node->m_网络.m_接收数据量)) != SOCKET_ERROR) {

                //uLongf len_dest = 1024;
                //auto errComp = uncompress(转换指针, &len_dest, (uint8*)pszRecv, nbSize);

                uint16 行ID = *((uint16*)pszRecv);
                //std::cout<< 行ID<<std::endl;
                memcpy(&p[256 * 行ID], pszRecv, 256);
            }
        }
        std::cout << "接收数据 : " << nbSize << std::endl;
        node->m_写入记录 = true;*/
        Sleep(3);
    }

    
    closesocket(s_accept);

    delete pszRecv;
}





//设置非阻塞
/*static void setnonblocking(int sockfd) {
    int flag = fcntl(sockfd, F_GETFL, 0);
    if (flag < 0) {
        Perror("fcntl F_GETFL fail");
        return;
    }
    if (fcntl(sockfd, F_SETFL, flag | O_NONBLOCK) < 0) {
        Perror("fcntl F_SETFL fail");
    }
}*/



C_UDP接收节点::C_UDP接收节点() : C_节点基类("UDP接收节点") {
    {
        C_插座基类* socket;
    }

    {
        WSADATA wsaData;
        
        if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
            printf("初始化失败.\n");
            return;
        }

        m_网络监听 = (S_结构对象指针)socket(AF_INET, SOCK_DGRAM, 0);

        SOCKADDR_IN* saClient = (SOCKADDR_IN*)malloc(sizeof(SOCKADDR_IN));
        saClient->sin_family = AF_INET;
        saClient->sin_port = htons(8000);             //发送端使用的发送端口，可以根据需要更改
        saClient->sin_addr.s_addr = htonl(INADDR_ANY);


        m_接收数据地址 = (S_结构对象指针)saClient;


        m_接收数据量 = sizeof(SOCKADDR_IN);
        if (bind((SOCKET)m_网络监听, (SOCKADDR FAR*)m_接收数据地址, m_接收数据量) != 0) {
            std::cout << "绑定端口初始化失败" << std::endl;
            return;
        }

    }

}

C_UDP接收节点::~C_UDP接收节点() {
    closesocket((SOCKET)m_网络监听);
    
}

bool C_UDP接收节点::f_update() {
    int32 nbSize = 0;

    int8* pszRecv = new int8[4096];
    if ((nbSize = recvfrom((SOCKET)m_网络监听, pszRecv, 4096, 0, (SOCKADDR FAR*)m_接收数据地址, &m_接收数据量)) != SOCKET_ERROR) {
        std::cout << "nbSize = " << nbSize << std::endl;
    }

    return false;
}












static uint16 g端口 = 8000;

C_UDP接收图像节点::C_UDP接收图像节点() : C_节点基类("UDP接收图像节点") {
    
    m_网络 = f_创建UDP网络监听(g端口);
    ++g端口;

    m_更新方式 = E_节点更新方式::e_节点更新_实时;

    C_插座基类* socket;
    DEF_创建图像插座_O(L"像素");




    m_PropISO = f_alloc_F32Prop(&m_ISO, L"ISO");
    m_Prop亮度 = f_alloc_F32Prop(&m_亮度, L"亮度");
    m_Prop帧数 = f_alloc_F32Prop(&m_帧数, L"帧数");
    m_Prop对比度 = f_alloc_F32Prop(&m_对比度, L"对比度");
    m_Prop饱和度 = f_alloc_F32Prop(&m_饱和度, L"饱和度");




    m_写入记录 = false;
    m_线程 = std::thread(f_接收UDP数据线程, this);
    m_运行线程 = true;
    m_线程.detach();
}

C_UDP接收图像节点::~C_UDP接收图像节点() {
    m_运行线程 = false;

    m_线程.joinable();
}

bool C_UDP接收图像节点::f_update() {
    int32 nbSize = 0;

    if (m_写入记录) {
        auto& pix = *DEF_图像插座Value(f_get输出插座(1));

        pix.m_维度 = { 图像大小.x, 图像大小.y, 1 };
        pix.m_颜色位数 = 4;
        pix.m_像素.resize(pix.m_维度.x * pix.m_维度.y * pix.m_维度.z);
        auto* d = pix.m_像素.data();
        auto* p = (uint8*)m_像素.data();


        for (uint32 i = 0; i < 512; ++i) {
        //Concurrency::parallel_for<uint32>(0, 1024, [&](uint32 i){
            for (uint32 j = 0; j < 512; ++j) {
                //d[i * 1024 + j] = f_rgb_to_rgba(p[i * 1024 + j]);
               // d[i * 图像大小.x + j] = f_rgb_to_rgba(p[i * 图像大小.x + j]);
                uint8 b = (p[i * 图像大小.x + j]);
                d[i * 图像大小.x + j].r = b;
                d[i * 图像大小.x + j].g = b;
                d[i * 图像大小.x + j].b = b;
                d[i * 图像大小.x + j].a = 255;
            }
        //});
        }
        m_写入记录 = false;
    }
    
    return false;
    //pix.m_像素.resize(1024*1024*3);
    //auto* p = pix.m_像素.data();

}













C_节点基类* f_node_UDP接收节点(S_设备环境& ctx, FILE* f) {
    C_UDP接收节点* node = new C_UDP接收节点();
    return node;
}

C_节点基类* f_node_UDP接收图像节点(S_设备环境& ctx, FILE* f) {
    C_UDP接收图像节点* node = new C_UDP接收图像节点();

    return node;
}










